home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 06 - 1990 / 06.03 Mar 90 / Mouse Source / TrackEdit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-10-23  |  7.6 KB  |  312 lines  |  [TEXT/KAHL]

  1. /*                                            TrackEdit.c                                            */
  2. /*
  3.  * Copyright © 1989 Martin Minow. All rights reserved.
  4.  *
  5.  * TrackCut(track_handle)
  6.  * track_handle    The TrackRecord handle
  7.  *
  8.  * Cut the selection to the Track private scrap.
  9.  * Anything currently in the scrap is deleted.  If there
  10.  * is no selection, the scrap is emptied.
  11.  *
  12.  * TrackCopy(track_handle)
  13.  * track_handle    The TrackRecord handle
  14.  *
  15.  * Copy the selection to the Track private scrap.
  16.  * Anything currently in the scrap is deleted.  If there
  17.  * is no selection, the scrap is emptied.
  18.  *
  19.  * TrackPaste(track_handle)
  20.  * track_handle    The TrackRecord handle
  21.  *
  22.  * Replace the selection range with the contents of the
  23.  * Track private scrap.  If the scrap is empty, the
  24.  * selection range is deleted.  The private scrap is
  25.  * not changed.
  26.  *
  27.  * TrackDelete(track_handle)
  28.  * track_handle    The TrackRecord handle
  29.  *
  30.  * Delete the selection range, but do not copy it to
  31.  * the Track private scrap.
  32.  */
  33.  
  34. #include    "TrackEdit.h"
  35. #define TR    (*tr)
  36. #define LEFT        FALSE
  37. #define RIGHT        TRUE
  38. #define NIL            0L
  39. #define NOT_NIL    1L
  40.  
  41. static void                do_paste(TrackHandle);
  42. static void                do_clear(TrackHandle, Boolean);
  43. static Boolean        is_at_space(TrackPtr, Boolean);
  44. static Boolean        is_at_word(TrackPtr, DOT, DOT, Boolean);
  45.  
  46. /*
  47.  * TrackCut(track_handle)
  48.  * Copy the selection to the scrap, then remove it.
  49.  */
  50. void
  51. TrackCut(track_handle)
  52. TrackHandle    track_handle;
  53. {
  54.         TrackCopy(track_handle);
  55.         TrackDelete(track_handle);
  56. }
  57.  
  58. /*
  59.  * TrackCopy(track_handle)
  60.  * Copy the selection to the scrap.
  61.  * This is the only routine to change TrackScrpHandle.
  62.  */
  63. void
  64. TrackCopy(track_handle)
  65. TrackHandle    track_handle;
  66. {
  67.         register TrackPtr    tr;
  68.         _Track_state            state;
  69.         register long            size;
  70.         
  71.         tr = _Track_lock(track_handle, &state);
  72.         size = TR.selEnd - TR.selStart;
  73.         SetHandleSize(TrackScrpHandle, size);
  74.         if (MemErr == noErr) {
  75.             BlockMove(
  76.                 &(*TR.hText)[TR.selStart],
  77.                 *TrackScrpHandle,
  78.                 size
  79.             );
  80.             TrackScrpLength = size;
  81.         }
  82.         _Track_unlock(&state);
  83. }
  84.  
  85. /*
  86.  * TrackPaste(track_handle)
  87.  * Replace the selection with the scrap
  88.  */
  89. void
  90. TrackPaste(track_handle)
  91. TrackHandle    track_handle;
  92. {
  93.         _Track_state    state;
  94.  
  95.         _Track_lock(track_handle, &state);
  96.         _Track_do_paste(track_handle);
  97.         _Track_unlock(&state);
  98. }
  99.  
  100. /*
  101.  * TrackDelete(track_handle)
  102.  * Remove the selection.
  103.  */
  104. void
  105. TrackDelete(track_handle)
  106. TrackHandle    track_handle;
  107. {
  108.         _Track_state    state;
  109.         
  110.         _Track_lock(track_handle, &state);
  111.         _Track_do_clear(track_handle, TRUE, TRUE);
  112.         _Track_unlock(&state);
  113. }
  114.  
  115. /*
  116.  * _Track_do_paste(track_handle)
  117.  * If a selection exists, remove it; then insert the
  118.  * current scrap.  Select the newly-inserted data.
  119.  * Use "intelligent paste" if available.  Note that
  120.  * _Track_do_paste() may unlock the TrackRecord
  121.  * temporarily.
  122.  */
  123. void
  124. _Track_do_paste(track_handle)
  125. TrackHandle    track_handle;
  126. {
  127.         register TrackPtr    tr;
  128.         _Track_state            state;
  129.         DOT                                start;
  130.         
  131.         tr = *track_handle;
  132.         _Track_caret(tr, _Track_caret_off);
  133.         _Track_do_clear(track_handle, FALSE, TRUE);
  134.         tr = *track_handle;
  135.         start = TR.selStart;
  136.         /*
  137.          * This is needed only for "intelligent paste."
  138.          * Insert a space before the selection if there
  139.          * is a word before the selection.
  140.          */
  141.         if (is_at_word(tr, 0, TR.selStart, RIGHT)) {
  142.             _Track_do_insert(tr, TR.selStart, " ", 1L);
  143.             TR.selStart++;
  144.         }
  145.         HLock(TrackScrpHandle);
  146.         _Track_do_insert(
  147.             tr, TR.selStart, *TrackScrpHandle, TrackScrpLength);
  148.         HUnlock(TrackScrpHandle);
  149.         TR.selEnd = TR.selStart + TrackScrpLength;
  150.         /*
  151.          * This is needed only for "intelligent paste."
  152.          * Insert a space after the selection if there
  153.          * is a word after the selection.
  154.          */
  155.         if (is_at_word(tr, TR.selEnd, TR.textLength, LEFT))
  156.             _Track_do_insert(tr, TR.selEnd, " ", 1L);
  157.         _Track_rebuild(track_handle, start);
  158. }
  159.  
  160. /*
  161.  * _Track_do_insert(track_ptr, offset, src, size)
  162.  * Stuff something into the text.
  163.  */
  164. void
  165. _Track_do_insert(tr, offset, src, size)
  166. TrackPtr    tr;
  167. long            offset;
  168. Ptr                src;
  169. long            size;
  170. {
  171.         Munger(TR.hText, offset, NIL, 0L, src, size);
  172.         if (MemErr == noErr)
  173.             TR.textLength = GetHandleSize(TR.hText);
  174. }
  175.  
  176. /*
  177.  * _Track_do_clear(track_handle, rebuild, smart)
  178.  * If a selection exists, delete it; then rebuild the
  179.  * lineStarts vector if requested. Use "intelligent cut"
  180.  * if available and smart is TRUE.  _Track_do_clear() may
  181.  * temporarily unlock the TrackRecord.
  182.  */
  183. void
  184. _Track_do_clear(track_handle, rebuild, smart)
  185. TrackHandle    track_handle;
  186. Boolean            rebuild;
  187. Boolean            smart;
  188. {
  189.         register TrackPtr        tr;
  190.         long                                size;
  191.         
  192.         tr = (*track_handle);
  193.         if (TR.selEnd != TR.selStart) {
  194.             /*
  195.              * There is a selection.  If the character to the
  196.              * left or right of the current selection is a
  197.              * space, cut it along with the selection.
  198.              * is_at_space() fails if "intelligent cut and
  199.              * paste" is disabled.
  200.              */
  201.             if (smart) {
  202.                 if (is_at_space(tr, LEFT))
  203.                     --TR.selStart;
  204.                 else if (is_at_space(tr, RIGHT))
  205.                     ++TR.selEnd;
  206.             }
  207.             size = TR.selEnd - TR.selStart;
  208.             Munger(TR.hText, TR.selStart, NIL, size, NOT_NIL, 0);
  209.             TR.textLength -= size;
  210.             SetHandleSize(TR.hText, TR.textLength);
  211.             TR.selEnd = TR.selStart;
  212.             if (rebuild)
  213.                 _Track_rebuild(track_handle, TR.selStart);
  214.         }
  215. }
  216.  
  217. /*
  218.  * is_at_space(direction)
  219.  * Use the ScriptMgr FindWord procedure to determine if
  220.  * the designated end of the selection is a word with an
  221.  * adjacent space. It is needed only for "intelligent
  222.  * cut and paste."
  223.  */
  224. static Boolean
  225. is_at_space(tr, direction)
  226. register TrackPtr    tr;
  227. Boolean                    direction;
  228. {
  229.         if (direction == LEFT) {
  230.             if (TR.selStart > 0
  231.              && is_at_word(tr, TR.selStart, TR.selEnd, LEFT)
  232.              && _Track_is_white(tr, *(TR.hText), TR.selStart-1))
  233.                 return (TRUE);
  234.         }
  235.         else /* RIGHT */ {
  236.             if (TR.selEnd < TR.textLength
  237.              && is_at_word(tr, TR.selStart, TR.selEnd, RIGHT)
  238.              && _Track_is_white(tr, *(TR.hText), TR.selEnd))
  239.                 return (TRUE);
  240.         }
  241.         return (FALSE);
  242. }
  243.  
  244. /*
  245.  * is_at_word(track_ptr, start, end, direction)
  246.  * Use FindWord to decide whether start..end is a word at
  247.  * the designated end.  This routine is needed only if
  248.  * you want "intelligent cut and paste."
  249.  */
  250. static Boolean
  251. is_at_word(tr, start, end, direction)
  252. register TrackPtr    tr;
  253. DOT                                start;
  254. DOT                                end;
  255. Boolean                        direction;
  256. {
  257.         OffsetTable                offsets;
  258.         
  259.         /*
  260.          * This table has a bit set for characters that form
  261.          * words. The bits are "numbered" from the left.
  262.          * We need it to check on one-character selections
  263.          * as they might be punctuation.
  264.          */
  265.         static long                word_break[] = {
  266.             0x00000000, 0x0000FFC0,    /* 00..3F    (allow digits)    */         
  267.             0x7FFFFFE1, 0x7FFFFFE0,    /* 40..7F    (allow letters)    */
  268.             0xFFFFFFFF, 0x01030003,    /* 80..BF    (int'l letters)    */
  269.             0x001F0080, 0x00000000    /* C0..FF (a few more)        */
  270.         };
  271.         
  272.         if (TR.wordBreak != NIL) {
  273.             if (direction == LEFT)
  274.                 return (_Track_is_white(tr, *TR.hText, start));
  275.             else {
  276.                 return (_Track_is_white(tr, *TR.hText, end));
  277.             }
  278.         }
  279.         if (!_Track_is_set(tr, _Track_use_script_manager)
  280.          || !_Track_is_set(tr, _Track_use_smart_cut_paste))
  281.             return (FALSE);            
  282.         if (direction == LEFT)
  283.             FindWord(*TR.hText, end, start, TRUE, NIL, offsets);
  284.         else {
  285.             FindWord(*TR.hText, end, end, FALSE, NIL, offsets);
  286.         }
  287. #if smgrVers >= 0x0210    /* See ScriptMgr.h                        */
  288.         /*
  289.          * In Think C version 4, the offset table is defined
  290.          * as a 3-element structure.
  291.          */
  292. #define START    offsets[0].offFirst
  293. #define END        offsets[0].offSecond
  294. #else
  295.         /*
  296.          * This is specific to Think C version 3, where the
  297.          * offset table is defined as a 6-element short vector.
  298.          * Warning: no longer tested.
  299.          */
  300. #define START    offsets[0]
  301. #define    END        offsets[1]
  302. #endif
  303.         if ((END - START) == 1) {
  304.             return (
  305.                 BitTst(word_break, (*TR.hText)[START])
  306.             );
  307.         }
  308.         else {
  309.             return ((END > START) ? TRUE : FALSE);
  310.         }
  311. }
  312.